#include "serv_socket_handle.h"
#include <sys/types.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <event2/event.h>
#include <event2/dns.h>
#include <event2/dns_struct.h>
#include <event2/util.h>

#ifdef _EVENT_HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include "log.h"
#include "format.h"
#include "user.h"
#include "rsa.h"
#include "utility.h"
#include "log.h"
#include "sha2.h"
#include "userSqliteOp.h"
#include "chartSqliteOp.h"
#include "user.h"
#include "KernelList.h"


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic warning "-Wunused-variable"
#pragma GCC diagnostic warning "-Wformat"
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
#pragma GCC diagnostic warning "-Wunreachable-code"
#pragma GCC diagnostic warning "-Waddress"
#pragma GCC diagnostic warning "-Warray-bounds"
#pragma GCC diagnostic warning "-Wchar-subscripts"
#pragma GCC diagnostic warning "-Wimplicit-int"
#pragma GCC diagnostic warning "-Wimplicit-function-declaration"
#pragma GCC diagnostic warning "-Wcomment"
#pragma GCC diagnostic warning "-Wmain"
#pragma GCC diagnostic warning "-Wmissing-braces"
#pragma GCC diagnostic warning "-Wnonnull"
#pragma GCC diagnostic warning "-Wparentheses"
#pragma GCC diagnostic warning "-Wpointer-sign"
#pragma GCC diagnostic warning "-Wreturn-type"
#pragma GCC diagnostic warning "-Wsequence-point"
#pragma GCC diagnostic warning "-Wsign-compare"
#pragma GCC diagnostic warning "-Wstrict-aliasing"
#pragma GCC diagnostic warning "-Wswitch"
#pragma GCC diagnostic warning "-Wtrigraphs"
#pragma GCC diagnostic warning "-Wuninitialized"
#pragma GCC diagnostic warning "-Wunknown-pragmas"
#pragma GCC diagnostic warning "-Wunused-label"
#pragma GCC diagnostic warning "-Wunused-value"

#pragma GCC diagnostic error "-Wformat"
#pragma GCC diagnostic error "-Wdeprecated-declarations"
#pragma GCC diagnostic error "-Wunreachable-code"



//数据库缓冲,因为数据库锁粒度比较大且耗时大,不能频繁操作
static struct _SQLITE_BUF_ {
    struct list_head user;  //对应user表中的数据
    struct list_head chart; //对应chart表中的数据
}sqliteBuf = {
    .user.next = &sqliteBuf.user,
    .user.prev = &sqliteBuf.user,
    .chart.next = &sqliteBuf.user,
    .chart.prev = &sqliteBuf.user,
};

/**
 * @brief  文件校验需要用到的一个回调函数
 * @note   
 * @param  *fp: 文件指针
 * @param  length: data的长度
 * @param  *data: 散列值保存地址
 * @retval 
 */
static int get_data(void *fp, size_t length, void *data)
{
    return fread(data, 1, length, (FILE *)fp);
}
/**
 * @brief  创建TCP套接字
 * @note   
 * @param  tcpPort: 需要监听的tcp端口号
 * @retval 失败返回-1，成功返回一个合法的套接字地址
 */
int create_tcp_sockfd(int16_t tcpPort)
{
    int on = 1;
    evutil_socket_t fd = -1;
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(tcpPort);

    /* 1.创建 */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        add_log("socket() error");
        exit(-1);
    }
    /* 2.设置为非阻塞 */
    if (evutil_make_socket_nonblocking(fd) < 0)
    {
        evutil_closesocket(fd);
        add_log("evutil_make_socket_nonblocking() error");
        return -1;
    }
    /* 3.保活 */
    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)) < 0)
    {
        evutil_closesocket(fd);
        add_log("setsockopt() error");
        return -1;
    }
    /* 4.地址重用 */
    if (evutil_make_listen_socket_reuseable(fd) < 0)
    {
        evutil_closesocket(fd);
        add_log("evutil_make_listen_socket_reuseable() error");
        return -1;
    }
    /* 5.绑定 */
    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        perror("bind()");
        evutil_closesocket(fd);
        add_log("bind() error");
        return -1;
    }
    return fd;
}
/**
 * @brief  创建UDP套接字
 * @note   
 * @param  tcpPort: 监听的端口
 * @retval 成功返回一个合法的套接字，失败返回-1
 */
int create_udp_sockfd(int16_t tcpPort)
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        add_log("socket() error");
        return -1;
    }
    struct sockaddr_in my_addr;
    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(tcpPort);
    //my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
    {
        evutil_closesocket(sockfd);
        add_log("bind()");
        return -1;
    }
    // if (evutil_make_socket_nonblocking(sockfd) < 0)
    // {
    //     evutil_closesocket(sockfd);
    //     return -1;
    // }
    if (evutil_make_listen_socket_reuseable(sockfd) < 0)
    {
        evutil_closesocket(sockfd);
        return -1;
    }

    return sockfd;
}

/**
 * @brief  新TCP连接回调函数
 * !@note  暂时没有心跳机制 
 * @param  *listener: 本程序未用到
 * @param  fd: 套接字句柄
 * @param  *cliAddr: 客户端地址
 * @param  socklen: 客户端地址结构体长度
 * @param  *user_data: evconnlistener_new_bind()传的参数
 * @retval None
 */
void new_connect_cb(struct evconnlistener *listener, evutil_socket_t fd,
                    struct sockaddr *cliAddr, int socklen, void *user_data)
{
    //心跳包频率,4s
    //static const struct timeval heartbeat = {4, 0};
    struct event_base *base = (struct event_base *)user_data;

    fprintf(stderr,"connection from %s,port:%d,sockfd:%d\n",
           inet_ntoa(((struct sockaddr_in *)cliAddr)->sin_addr),
           ntohs(((struct sockaddr_in *)cliAddr)->sin_port),
           fd);
    add_log("connection from %s,port:%d,sockfd:%d\n",
            inet_ntoa(((struct sockaddr_in *)cliAddr)->sin_addr),
            ntohs(((struct sockaddr_in *)cliAddr)->sin_port),
            fd);
    //为这个客户端分配一个 bufferevent，释放时关闭套接字，使用锁会失败
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    assert(bev != NULL);
    bufferevent_setwatermark(bev, EV_READ, 6, 1024); //调整水位
    bufferevent_setcb(bev, tcp_read_cb, NULL, tcp_event_cb, NULL);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);
    //bufferevent_set_timeouts(bev, &heartbeat, NULL);
}

/**
 * @brief  主要是超时事件与连接关闭事件的处理
 * @note   
 * @param  *bev: 可看做读写句柄
 * @param  events: 发生的事件
 * @param  *arg: 在new_connect_cb()函数中传入的，可以是任意值
 * @retval None
 */
void tcp_event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
        fprintf(stderr,"tcp_event_cb() connection closed\n");
    }
    else if (events & BEV_EVENT_ERROR)
    {
        fprintf(stderr,"some other error\n");
    }
    else if (events & BEV_EVENT_CONNECTED)
    {
        // 程序没有监听这个事件
        fprintf(stderr,"We finished a requested connection on the bufferevent\n");
        return;
    }
    else if (events & BEV_EVENT_TIMEOUT)
    {
        /* 注意，若触发了timeout事件，那么read事件会被disable，此时若想继续运行，需要重新enable read事件*/
        fprintf(stderr,"BEV_EVENT_TIMEOUT\n");
    }
    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
}
/**
 * @brief  接收到客户端数据时调用此函数
 * @note   
 * @param  *bev: 可看成文件读写句柄(实际远不止于此)
 * @param  *arg: 设置它的函数传入的，可以是任意值
 * @retval None
 */
void tcp_read_cb(struct bufferevent *bev, void *arg)
{
    pthread_t read_tid;
    SOCK_BUFFER *sock_buf = (SOCK_BUFFER *)calloc(1, sizeof(SOCK_BUFFER));
    assert(sock_buf != NULL);
    sock_buf->m_sock_type = SOCK_TYPE_BUFFERENT;
    sock_buf->m_bev = bev;

    pthread_attr_t attr;
    int err = pthread_attr_init(&attr);
    assert(err ==0);
    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    assert(err == 0);
    /* 这里是不符合规范，在这里申请，理应在这里释放 */
    err = pthread_create(&read_tid, NULL, read_cb_thread, sock_buf);
    assert(err == 0);
    pthread_attr_destroy(&attr);
}
/**
 * @brief  UDP套接字可读时调用这个函数
 * !@note  这个函数中申请了内存，但是内存是在子线程中释放的，有泄漏的隐患，但是本程序在尽量避免 
 * @param  sockfd: 从这个句柄读取客户端发送的数据
 * @param  event: 发生的事件
 * @param  *arg: 可以是任意值
 * @retval None
 */
void udp_read_cb(int sockfd, short event, void *arg)
{
    pthread_t read_tid;
    SOCK_BUFFER *sock_buf = (SOCK_BUFFER *)calloc(1, sizeof(SOCK_BUFFER));
    assert(sock_buf != NULL);
    sock_buf->m_sock_type = SOCK_TYPE_DGRAM;
    sock_buf->m_sockfd = sockfd;
    sock_buf->m_size = sizeof(struct sockaddr);
    /* 1.注意这里是不符合规范的，在这里申请，理应在这里释放，但是实际情况不允许 */
    int err = pthread_create(&read_tid, NULL, read_cb_thread, sock_buf);
    assert(err == 0);
}
/**
 * @brief  如果是tcp连接就释放该连接
 * @note   
 * @param  *bev: 可看成套接字读写句柄
 * @retval None
 */
void del_user(SOCK_BUFFER *bev)
{
    if (bev->m_sock_type == SOCK_TYPE_BUFFERENT)
    {
        bufferevent_free(bev->m_bev);
    }
}
/**
 * @brief  实现自定义文件句柄SOCK_BUFFER的读
 * @note   
 * @param  *bev: 自定义文件句柄
 * @param  *buf: 读取字节保存地址
 * @param  size: 需要读取的字节数
 * @retval 返回成功读取的字节数
 */
int sock_buffer_read(SOCK_BUFFER *bev, char *buf, size_t size)
{
    int count = 0;
    if (bev->m_sock_type == SOCK_TYPE_BUFFERENT)
    {
        count = bufferevent_read(bev->m_bev, buf, size);
    }
    else if (bev->m_sock_type == SOCK_TYPE_DGRAM)
    {
        count = recvfrom(bev->m_sockfd, buf, size, 0, &bev->m_addr, &bev->m_size);
    }
    else
    {
        count = 0;
    }
    return count;
}
/**
 * @brief  实现自定义文件句柄SOCK_BUFFER的写
 * @note   
 * @param  *bev: 自定义的文件句柄
 * @param  *buf: 需要写入网卡的字符串地址
 * @param  size: 需要写入的大小
 * @retval 返回成功写入的字节数
 */
int sock_buffer_write(SOCK_BUFFER *bev, char *buf, size_t size)
{
    int count = 0;
    if (bev->m_sock_type == SOCK_TYPE_BUFFERENT)
    {
        count = bufferevent_write(bev->m_bev, buf, size);
    }
    else if (bev->m_sock_type == SOCK_TYPE_DGRAM)
    {
        count = sendto(bev->m_sockfd, buf, size, 0, &bev->m_addr, bev->m_size);
    }
    else
    {
        count = 0;
    }
    return count;
}
/**
 * @brief  读一个TCP套接字
 * @note   
 * @param  *arg: 需要传入SOCK_BUFFER 结构体
 * @retval None
 */
void *read_cb_thread(void *arg)
{
    SOCK_BUFFER *bev = arg;
    char buf[MAX_BUF_SIZE];
    char *p_buf = buf;
    bzero(buf, MAX_BUF_SIZE);
    int count = 0; //记录读到的字节数
    unsigned short cmd_num = 0;
    unsigned int packet_len = 0;

    /* 1.先读包头 */
    if (bev->m_sock_type == SOCK_TYPE_BUFFERENT)
    {
        count = sock_buffer_read(bev, buf, Msg.m_msg_len);
    }
    else
    {
        //如果是UDP需要一次读取整个包
        count = sock_buffer_read(bev, buf, MAX_BUF_SIZE);
    }
    if (count < 6)
    {
        fprintf(stderr,"messages is less than 6\n");
        del_user(bev); //关掉这个套接字
        free(bev);
        return NULL;
    }

    /* 4.正常读数据 */
    head_analyze(buf, &cmd_num, &packet_len);
    if (bev->m_sock_type == SOCK_TYPE_BUFFERENT)
    {
        count = sock_buffer_read(bev, buf, packet_len);
    }
    else
    {
        count -= Msg.m_msg_len;
        p_buf = p_buf + Msg.m_msg_len;
    }
    if ((unsigned)count < packet_len)
    {
        fprintf(stderr,"cmd_num = %d,count = %d, packet_len = %d\n", cmd_num, count, packet_len);
        fprintf(stderr,"read failed!??\n");
        free(bev);
        return NULL;
    }
    deal_server_recv(bev, cmd_num, packet_len, p_buf);
    free(bev);
    return NULL;
}
/**
 * @brief  处理去掉报头后的数据
 * @note   
 * @param  *bev: 套接字读写句柄
 * @param  cmd: 命令 @ref enum MESSAGETYPE
 * @param  packet_len: buf的长度
 * @param  *buf: 客户发送的字符串
 * @retval 成功返回0，失败返回-1
 */
int deal_server_recv(SOCK_BUFFER *bev, u_int16_t cmd, u_int32_t packet_len, char *buf)
{
    signed int err = 0;
    u_int64_t id = 0;
    char send_cmd[MAX_BUF_SIZE];

    switch (cmd)
    {
    case E_MSG_DEBUG:
        fprintf(stderr,"recv: %s", buf);
        break;
    case E_MSG_LOGIN:       //用户登录
    {
        //登录
        fprintf(stderr,"\rlogin request\n");
        err = user_confirmation(bev, buf, packet_len);
        break;
    }
	case E_MSG_TIMESTAMP:
        fprintf(stderr,"serv: E_MSG_TIMESTAMP\n");
        break;
    case E_MSG_BEG_TIMESTAMP:
        break;
    case E_MSG_BEG_FILE_LIST:
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = send_current_path_file_list(bev);
        }
        break;
    case E_MSG_GET_FILE:
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = send_file_to_client(bev, (uint32_t)(uint8_t)buf[0], buf + NAME_PASSWD_SESSION_LEN);
        }
        break;
    case E_MSG_CONTINUE:
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = continue_send((uint32_t)(uint8_t)buf[0], bev);
        }
        break;
    case E_MSG_FILE_HEAD:
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = save_client_file_head((uint32_t)(uint8_t)buf[0], buf + NAME_PASSWD_SESSION_LEN, packet_len - NAME_PASSWD_SESSION_LEN, bev);
        }
        break;
    case E_MSG_FILE_CONTENT:
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = save_client_file_content(buf + NAME_PASSWD_SESSION_LEN, packet_len - NAME_PASSWD_SESSION_LEN, (uint32_t)(uint8_t)buf[0]);
        }
        break;
    case E_MSG_FILE_END: //客户端文件发送完了，需要进行校验
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = check_client_file((uint32_t)(uint8_t)buf[0]);
        }
        break;
    case E_MSG_GET_DIALOG_LIST: //获取会话列表
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            err = sendDialogList(bev,id);
        }
        break;
    case E_MSG_GET_DIALOG_PERSON_INFO:  //获取用户信息
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            u_int64_t chartId = 0;
            memcpy(&chartId,buf+NAME_LEN+sizeof(u_int64_t),sizeof(u_int64_t));
            err = sendDialogPersonInfo(bev,id,chartId);
        }
        break;
    case E_MSG_USER_SEND_MESSAGE:   //保存用户发送的消息
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            u_int64_t chartId = 0;
            memcpy(&chartId,buf+NAME_LEN+sizeof(u_int64_t),sizeof(u_int64_t));
            add_log("用户id '%llu' 向 会话id '%llu' 发送了一条消息\n",(unsigned long long)id,(unsigned long long)chartId);
            err = insert1ChartRecord(chartId,id, "unknow", buf+NAME_LEN+sizeof(u_int64_t)*2);
        }
        else{
            fprintf(stderr,"err:%s\n","session 错误");
        }
        break;
    case E_MSG_GET_HISTORY_MESSAGE: //获取历史消息
        
    case E_MSG_GET_LATEST_MESSAGE:  //查询最近的信息
        err = is_session_correct(buf,&id);
        if (err == E_MSG_SUCCESS)
        {
            u_int64_t chartId = 0;
            memcpy(&chartId,buf+NAME_LEN+sizeof(u_int64_t),sizeof(u_int64_t));
            err = sendHistoryMessage(bev,id,chartId);
        }
        break;
    default:
        fprintf(stderr,"unknow cmd\n");
        return -1;
    }

    if (err)
    {
        head_package(send_cmd, err, 0);
        sock_buffer_write(bev, send_cmd, Msg.m_msg_len);
    }
    return 0;
}
/**
 * @brief  文件任务结构体初始化
 * @note   
 * @param  user_num: 
 * @param  *name: 
 * @retval 
 */
int file_task_init(uint32_t user_num, const char *name)
{
    if (user_num < 0 || user_num >= g_all_data->user_number)
    {
        return E_MSG_WRONG_SESSION;
    }
    USER_DATA *user = g_all_data->user_data_addr + user_num;
    if (user->file_task.up_down != FILE_NONE)
    {
        return E_MSG_TRANS_EXIT;
    }
    /* 1. 检查是文件还是目录 */
    struct stat st;
    stat(name, &st);
    if (S_ISDIR(st.st_mode))
    {
        user->file_task.up_down = FILE_NONE;
        return E_MSG_FILE_IS_DIR;
    }
    FILE *fp = fopen(name, "rb");
    if (fp == NULL)
    {
        fprintf(stderr,"open %s, %s\n", name, strerror(errno));
        return E_MSG_FILE_NAME_ERROR;
    }

    bzero(user->file_task.sha256, 64);
    sha256Universal(get_data, fp, (char *)user->file_task.sha256);
    assert(fseek(fp, 0, SEEK_END) == 0);
    user->file_task.file_size = (uint32_t)ftell(fp);
    user->file_task.finished_size = 0;
    user->file_task.up_down = FILE_DOWN;
    memcpy((char *)user->file_task.file_name, name, strlen(name) + 1);
    fclose(fp);
    return E_MSG_SUCCESS;
}
/**
 * @brief  发送文件任务结构体给客户端
 * @note   
 * @param  *bev: 
 * @param  *file_task: 
 * @retval 
 */
int send_file_head_to_client(SOCK_BUFFER *bev, FILE_TRANS_TASK *file_task)
{
    char send_cmd[MAX_BUF_SIZE];
    bzero(send_cmd, MAX_BUF_SIZE);

    /* 1.发送文件头 */
    head_package(send_cmd, E_MSG_FILE_HEAD, sizeof(FILE_TRANS_TASK));
    memcpy((char *)send_cmd + Msg.m_msg_len, (char *)file_task, sizeof(FILE_TRANS_TASK));
    sock_buffer_write(bev, send_cmd, Msg.m_msg_len + sizeof(FILE_TRANS_TASK));
    fprintf(stderr,"正在进行文件传输...\n");
    return E_MSG_SUCCESS;
}
/**
 * @brief  根据用户索引继续发送文件内容
 * @note   
 * @param  user_num: 用户索引
 * @param  *bev: 
 * @retval 
 */
int continue_send(uint32_t user_num, SOCK_BUFFER *bev)
{
    char send_cmd[MAX_BUF_SIZE];
    if (user_num < 0 || user_num >= g_all_data->user_number)
    {
        return E_MSG_WRONG_SESSION;
    }
    USER_DATA *user = g_all_data->user_data_addr + user_num;
    FILE_TRANS_TASK *file_task = &user->file_task;
    FILE *fp = fopen((char *)file_task->file_name, "rb");
    if (fp == NULL)
    {
        fprintf(stderr,"%s\n", strerror(errno));
        file_task->up_down = FILE_NONE;
        return E_MSG_FILE_NAME_ERROR;
    }

    fseek(fp, file_task->finished_size, SEEK_SET);
    uint32_t send_len = MIN(file_task->file_size - file_task->finished_size, MAX_BUF_SIZE - Msg.m_msg_len);
    if (send_len > 0)
    {
        int num = fread((char *)send_cmd + Msg.m_msg_len, 1, send_len, fp);
        if (num < 0)
        {
            FCLOSE(fp);
            file_task->up_down = FILE_NONE;
            fprintf(stderr, "error when read\n");
            return E_MSG_FILE_TRANS_ERROR;
        }
        file_task->finished_size += (uint32_t)send_len;//如果文件有删减交给客户端去校验
        head_package(send_cmd, E_MSG_FILE_CONTENT, num);
        sock_buffer_write(bev, send_cmd, Msg.m_msg_len + num);
        fprintf(stderr,"\r已发送 %d/%d      ", file_task->finished_size, file_task->file_size);
    }
    else
    {
        /* 3.结束文件传输 */
        head_package(send_cmd, E_MSG_FILE_END, 0);
        sock_buffer_write(bev, send_cmd, Msg.m_msg_len);
        fprintf(stderr, "\n文件发送完毕...\n");
        file_task->up_down = FILE_NONE;
    }
    FCLOSE(fp);
    return E_MSG_SUCCESS;
}
/**
 * @brief  校验文件
 * @note   
 * @param  user_num: 用户索引
 * @retval 
 */
int check_client_file(uint32_t user_num)
{
    /* 1.检查用户索引 */
    if (user_num < 0 || user_num >= g_all_data->user_number)
    {
        return E_MSG_WRONG_SESSION;
    }
    USER_DATA *user = g_all_data->user_data_addr + user_num;
    fprintf(stderr,"\n文件接收完成，正在校验文件...\n");
    /* 1.校验文件 */
    char output[64];
    bzero(output, 64);
    fseek(user->fp, 0, SEEK_SET);
    sha256Universal(get_data, user->fp, output);
    FCLOSE(user->fp);
    if (memcmp(output, &user->file_task.sha256, 64) != 0)
    {
        fprintf(stderr,"文件不完整或经过篡改\n");
        fprintf(stderr,"check:%s\n", output);
        fprintf(stderr, "shoud:%s\n", user->file_task.sha256);
    }
    else
    {
        fprintf(stderr, "文件完整且内容未经篡改\n");
    }
    user->file_task.up_down = FILE_NONE;
    return E_MSG_SUCCESS;
}
/**
 * @brief  保存文件内容
 * @note   
 * @param  *buf: 
 * @param  packet_len: 
 * @param  user_num: 
 * @retval 
 */
int save_client_file_content(char *buf, uint32_t packet_len, uint32_t user_num)
{
    /* 1.检查用户索引 */
    if (user_num < 0 || user_num >= g_all_data->user_number)
    {
        return E_MSG_WRONG_SESSION;
    }
    /* 2.检查数据长度 */
    USER_DATA *user = g_all_data->user_data_addr + user_num;
    if (packet_len < 0 || packet_len > MAX_BUF_SIZE)
    {
        fprintf(stderr, "packet_len != sizeof(FILE_TRANS_TASK)");
        return E_MSG_FILE_TRANS_ERROR;
    }
    if (user->fp == NULL)
    {
        fprintf(stderr, "文件未打开\n");
        user->file_task.up_down = FILE_NONE;
        exit(-1);
    }
    int num = fwrite(buf, 1, packet_len, user->fp);
    if ((unsigned)num != packet_len)
    {
        perror("fwrite()");
        fprintf(stderr,"num = %d,packet_len = %d\n", num, packet_len);
        return E_MSG_FILE_TRANS_ERROR;
    }
    user->file_task.finished_size += num;
    fprintf(stderr, "\r已接收： %d/%d ", user->file_task.finished_size, user->file_task.file_size);

    return E_MSG_CONTINUE;
}
/**
 * @brief  保存客户端发送的文件任务结构体
 * @note   
 * @param  user_num: 
 * @param  *buf: 
 * @param  packet_len: 
 * @param  *bev: 
 * @retval 
 */
int save_client_file_head(uint32_t user_num, char *buf, uint32_t packet_len, SOCK_BUFFER *bev)
{
    /* 1.检查用户索引 */
    if (user_num < 0 || user_num >= g_all_data->user_number)
    {
        return E_MSG_WRONG_SESSION;
    }
    /* 2.检查数据长度 */
    USER_DATA *user = g_all_data->user_data_addr + user_num;
    if (packet_len != sizeof(FILE_TRANS_TASK))
    {
        fprintf(stderr, "packet_len != sizeof(FILE_TRANS_TASK)");
        return E_MSG_FILE_TRANS_ERROR;
    }

    /* 3.拷贝数据 */
    bzero(&user->file_task, sizeof(FILE_TRANS_TASK));
    memcpy(&user->file_task, buf, packet_len);
    if (user->file_task.up_down == FILE_UP)
    {
        if (user->file_task.finished_size != 0)
        {
            //如果是续传就追加方式打开
            user->fp = fopen((char *)user->file_task.file_name, "a+");
        }
        else
        {
            //如果是新建就直接清空方式打开或创建
            user->fp = fopen((char *)user->file_task.file_name, "w+");
        }
        if (user->fp == NULL)
        {
            perror("fopen()");
            return E_MSG_FILE_TRANS_ERROR;
        }
        int err = ftruncate(fileno(user->fp), user->file_task.finished_size);
        assert(err != -1);
    }
    else if (user->file_task.up_down == FILE_DOWN) //如果是客户端下载文件
    {
        return continue_send(user_num, bev);
    }
    else
    {
        add_log("unexpected result");
        return E_MSG_SUCCESS;
    }
    fseek(user->fp, user->file_task.finished_size, SEEK_SET);
    fprintf(stderr, "\n正在接收客户端文件 %s ......\n", user->file_task.file_name);
    return E_MSG_CONTINUE;
}
/**
 * @brief  根据用户索引发送文件内容给客户端
 * @note   
 * @param  *bev: 
 * @param  user_num: 
 * @param  *file_name: 
 * @retval 
 */
int send_file_to_client(SOCK_BUFFER *bev, uint32_t user_num, char *file_name)
{
    /* 1.规范文件名 */
    char *name = file_name;
    while (*name == ' ')
        name++;
    if (name[strlen(name) - 1] == '\n')
    {
        name[strlen(name) - 1] = 0; //添加结束符
    }
    /* 2.文件任务初始化 */
    int retval = file_task_init(user_num, name);
    if (retval == E_MSG_SUCCESS)
    {
        retval = send_file_head_to_client(bev, &(g_all_data->user_data_addr + user_num)->file_task);
    }
    return retval;
}
/** 
 * sendDialogList
 * @Descript:发送会话列表
 * @Author	:hezuoqiang
 * @DateTime:2019年11月3日T15:54:44+0800
 * @param	bev	:
 * @param	id	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int sendDialogList(SOCK_BUFFER *bev,u_int64_t id)
{
    int i=0;
    u_int64_t resultNum = 0;
    char *pDialogList = NULL;

    /* 1.查询会话列表 */
    int err = getDialogList(id,&resultNum,&pDialogList);
    UTIL_ASSERT(err == 0);

    /* 3.发送会话列表 */
    char send_cmd[MAX_BUF_SIZE];
    u_int64_t *pU64 = (u_int64_t *)pDialogList;
    head_package(send_cmd, E_MSG_GET_DIALOG_ONE, sizeof(u_int64_t)*2);
    for(i=0;(unsigned)i<resultNum;i++)
    {
        memcpy(send_cmd + Msg.m_msg_len,&pU64[i*2],sizeof(u_int64_t)*2);
        sock_buffer_write(bev, send_cmd, sizeof(u_int64_t)*2 + Msg.m_msg_len);
    }

    if(pDialogList)
    {
        free(pDialogList);
        pDialogList = NULL;
    }
    return E_MSG_GET_DIALOG_END;
}

/** 
 * sendHistoryMessage
 * @Descript:查询历史消息
 * @Author	:hezuoqiang
 * @DateTime:2019年11月4日T21:13:01+0800
 * @param	bev	:
 * @param	userId	:
 * @param	chartId	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int sendHistoryMessage(SOCK_BUFFER *bev,u_int64_t userId,u_int64_t chartId)
{
    int i=0;
    u_int64_t resultNum = 0;
    char *pMessage = NULL;
    
    /* 1.查询历史消息记录 */
    int err = getHistoryMessage(chartId,&resultNum,&pMessage);
    UTIL_ASSERT(err == 0);

    /* 3.逐条发送消息 */
    char send_cmd[MAX_BUF_SIZE];
    head_package(send_cmd, E_MSG_ONE_MESSAGE, (sizeof(u_int64_t)*3+NAME_LEN+CONTENT_LEN));
    for(i=resultNum-1;i>=0;i--)
    {
        memcpy(send_cmd + Msg.m_msg_len,pMessage+i*(sizeof(u_int64_t)*3+NAME_LEN+CONTENT_LEN),(sizeof(u_int64_t)*3+NAME_LEN+CONTENT_LEN));
        sock_buffer_write(bev, send_cmd, (sizeof(u_int64_t)*3+NAME_LEN+CONTENT_LEN) + Msg.m_msg_len);
    }

    if(pMessage)
    {
        free(pMessage);
        pMessage = NULL;
    }
    return E_MSG_END_MESSAGE;
}
/** 
 * sendDialogPersonInfo
 * @Descript:查找会话id的参与人员
 * @Author	:hezuoqiang
 * @DateTime:2019年11月4日T9:10:07+0800
 * @param	bev	:
 * @param	id	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int sendDialogPersonInfo(SOCK_BUFFER *bev,u_int64_t userId,u_int64_t chartId)
{
    int i=0;
    u_int64_t resultNum = 0;
    char *pDialogPersonList = NULL;

    /* 1.不是会话成员则加入到会话,会话不存在则创建并发送会话列表 */
    int err = joinInDialog(userId,chartId);
    sendDialogList(bev,userId);
    
    /* 2.查询参与会话的成员列表 */
    err = getDialogPersonList(chartId,&resultNum,&pDialogPersonList);
    UTIL_ASSERT(err == 0);
    
    /* 3.发送会话成员列表 */
    char send_cmd[MAX_BUF_SIZE];
    //u_int64_t *pU64 = (u_int64_t *)pDialogPersonList;
    head_package(send_cmd, E_MSG_GET_DIALOG_PERSON_INFO, sizeof(u_int64_t)*2+NAME_LEN);
    for(i=0;(unsigned)i<resultNum;i++)
    {
        char *p=pDialogPersonList+i*(sizeof(u_int64_t)*2+NAME_LEN);
        memcpy(send_cmd + Msg.m_msg_len,p,sizeof(u_int64_t)*2+NAME_LEN);
        //printf("%s,%s:%d:%llu,%llu,%s\n",__FILE__,__FUNCTION__,__LINE__,*(unsigned long long *)p,*(unsigned long long *)(p+8),p+16);
        sock_buffer_write(bev, send_cmd, sizeof(u_int64_t)*2+NAME_LEN + Msg.m_msg_len);
    }
    add_log("用户id '%llu' 加入了会话id '%llu'\n",(unsigned long long)userId,(unsigned long long)chartId);
    if(pDialogPersonList)
    {
        free(pDialogPersonList);
        pDialogPersonList = NULL;
    }
    return E_MSG_END_DIALOG_PERSON_INFO;
}
/**
 * @brief  发送当前工作路径下的文件名给客户端
 * @note   
 * @param  *bev: 读写句柄
 * @retval 
 */
int send_current_path_file_list(SOCK_BUFFER *bev)
{
    char send_cmd[MAX_BUF_SIZE];
    DIR *current_dir = opendir("./");
    if (current_dir == NULL)
    {
        perror("DIR open error");
        return E_MSG_SERVER_BUG;
    }
    struct dirent *dir_read = NULL;
    while (1)
    {
        dir_read = readdir(current_dir);
        if (dir_read == NULL)
        {
            break;
        }
        bzero(send_cmd, MAX_BUF_SIZE);
        snprintf(send_cmd + Msg.m_msg_len, MAX_BUF_SIZE - Msg.m_msg_len, "%s", dir_read->d_name);
        head_package(send_cmd, E_MSG_DEBUG, strlen(dir_read->d_name) + 1);
        sock_buffer_write(bev, send_cmd, strlen(dir_read->d_name) + 1 + Msg.m_msg_len);
    }
    return E_MSG_SUCCESS;
}
/**
 * @brief  检查session
 * @note   
 * @param  *session: 第一个字节是用户索引，后15个是session值
 * @retval 成功返回E_MSG_SUCCESS，失败返回E_MSG_WRONG_SESSION
 */
int is_session_correct(char *session, u_int64_t *Id)
{
    char *pId = session;
    char *pSession = session + sizeof(u_int64_t);
    memcpy(Id,pId,sizeof(u_int64_t));

    char sessionInDb[NAME_LEN];
    time_t timeNow = time(NULL);
    time_t timeInDb = 0;

    /* 1.查询session与上一次的活跃时间 */
    //printf("%s,%s:%d:id = %llu\n",__FILE__,__FUNCTION__,__LINE__,(unsigned long long)*Id);
    int ret = getUserSessionById(*Id,sessionInDb,&timeInDb);
    if(ret != 0 )
    {
        return E_MSG_WRONG_SESSION;
    }
    //printf("%s,%s:%d:timeNow = %lld,timeInDb = %lld\n",__FILE__,__FUNCTION__,__LINE__,(signed long long)timeNow,(signed long long)timeInDb);
    //printf("sessionInDb = %s\npSession = %s\n",sessionInDb,pSession);
#if _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
    long long int dist = llabs(timeNow - timeInDb);
#else
    long int dist = labs(timeNow - timeInDb);
#endif
    if(memcmp(sessionInDb,pSession,NAME_LEN)!=0 || dist >= 60*60)
    {
        return E_MSG_WRONG_SESSION;
    }
    return E_MSG_SUCCESS;
}
/**
 * @brief  验证用户名与密码，不存在该用户将创建
 * @note   
 * @param  *bev: 
 * @param  *buf: 加密的用户名与密码
 * @param  packet_len: 
 * @retval 
 */
int user_confirmation(SOCK_BUFFER *bev, void *buf, u_int32_t packet_len)
{
    /* 1.解密登陆信息 */
    int *encoded = buf;
    int retval = E_MSG_SUCCESS;
	u_int64_t id = 0;
    char *decoded = decodeMessage(packet_len / sizeof(int),
                                  key.m_private.m_bytes,
                                  encoded, key.m_private.m_exponent,
                                  key.m_private.m_modulus);
    char name[NAME_PASSWD_SESSION_LEN], passwd[NAME_PASSWD_SESSION_LEN];
    bzero(name, NAME_PASSWD_SESSION_LEN);
    bzero(passwd, NAME_PASSWD_SESSION_LEN);
    char *p1 = NULL, *p2 = NULL, *p3 = NULL;
    p1 = strstr(decoded, "$");
    if (p1 != NULL)
        p2 = strstr(p1 + 1, ";");
    if (p2 != NULL)
        p3 = strstr(p2 + 1, ";");
    if (p3 == NULL || p2-p1 <= 1 ||p3-p2 <= 1)
        return E_MSG_WRONG_PASSWD;
    *(p2) = '\0';
    *(p3) = '\0';
    memcpy(name, p1 + 1, MIN(p2 - p1 - 1, NAME_PASSWD_SESSION_LEN-1));
    memcpy(passwd, p2 + 1, MIN(p3 - p2 - 1, NAME_PASSWD_SESSION_LEN-1));
    fprintf(stderr,"name = %s\n", name);
    fprintf(stderr,"passwd = %s\n", passwd);

	/* 2.查找数据库中的用户名 */
	char passwdInDb[NAME_PASSWD_SESSION_LEN];
	bzero(passwdInDb,NAME_PASSWD_SESSION_LEN);
	int ret = getUserPasswordByName(name,passwdInDb,&id);
	// 2.1 查询成功
	if(ret == 0)
	{
		if(memcmp(passwd,passwdInDb,MAX(strlen(passwd),strlen(passwdInDb))) == 0)
		{
			retval = E_MSG_IDENTIFY_SUCCESS;
		}
		else
		{
			//puts(passwd);
			//puts(passwdInDb);
			add_log("用户:%s 企图使用密码'%s'进行登录但失败了\n",name,passwd);
			retval = E_MSG_WRONG_PASSWD;
		}
	}
	// 2.2 查询失败,可能是用户名不存在
	else
	{
		/* 2.2.2 向数据库中添加一条用户记录 */
		retval = getMaxUserId(&id);
		id++;
		if(retval != 0)
		{
			retval = E_MSG_REGIST_FILED;	//注册失败
		}
		retval = insertUserInfo(id,name,name,passwd);
		if (retval != SUCCESS)
	    {
	        retval = E_MSG_REGIST_FILED;	//注册失败
	    }
		else
		{
		    add_log("新用户:%s 进行了注册\n",name);
			retval = E_MSG_REGIST_SUCCESS;	//注册成功
		}
	}
	if(retval == E_MSG_REGIST_SUCCESS || retval == E_MSG_IDENTIFY_SUCCESS)
	{
		UTIL_ASSERT(generatSession(id) == 0);
		retval = sendUserInfo2Client(id,bev);
		add_log("用户:%s 通过了身份验证登录了服务器\n",name);
	}
    free(decoded);
    return retval;
}


/** 
 * sendUserInfo2Client
 * @Descript:发送用户数据给客户端
 * @Author	:hezuoqiang
 * @DateTime:2019年11月1日T9:52:33+0800
 * @param	id	:
 * @param	bev	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int sendUserInfo2Client(u_int64_t id,SOCK_BUFFER *bev)
{
	int retval = E_MSG_SUCCESS;
	USER user;
    retval = searchUserById(id, &user);
    if (retval != 0)
    {
        printf("search failed\n");
		retval = E_MSG_REGIST_FILED;
		goto exit;
    }
	char send_cmd[MAX_BUF_SIZE];
    bzero(send_cmd, MAX_BUF_SIZE);
	head_package(send_cmd, E_MSG_USER_INFO, sizeof(user));
    memcpy((char *)send_cmd + Msg.m_msg_len, &user, sizeof(user));
    sock_buffer_write(bev, send_cmd, Msg.m_msg_len + sizeof(user));
    add_log("finish send user info to %s;",user.name);
exit:
	return retval;
}
/**
 * @brief  通过bev查找用户，并给该用户发送session
 * !@note   因为这里只有读操作，所以没有加锁
 * @param  *bev: 
 * @retval 
 */
int send_session(SOCK_BUFFER *bev)
{
    char send_cmd[MAX_BUF_SIZE];
    bzero(send_cmd, MAX_BUF_SIZE);
    int i = 0;
    /* 1.查找用户 */
    USER_DATA *user = NULL;
    for (i = 0; (unsigned)i < g_all_data->user_number; i++)
    {
        user = g_all_data->user_data_addr + i;
        if (user->bev == bev->m_bev)
        {
            break;
        }
    }
    if ((unsigned)i >= g_all_data->user_number)
    {
        return E_MSG_WRONG_PASSWD;
    }
    /* 2.发送用户索引与session */
    send_cmd[6] = i;
    head_package(send_cmd, E_MSG_SESSION, NAME_PASSWD_SESSION_LEN);
    memcpy((char *)send_cmd + Msg.m_msg_len + 1, user->session, NAME_PASSWD_SESSION_LEN-1);
    sock_buffer_write(bev, send_cmd, Msg.m_msg_len + NAME_PASSWD_SESSION_LEN);
    add_log("findished send session");

    /* 3.检查是否存在需要续传的文件 */
    int retval = E_MSG_SUCCESS;
    if (user->file_task.up_down == FILE_UP)
    {
        retval = send_file_head_to_client(bev, &(user->file_task));
    }
    fprintf(stderr,"end of send_session()\n");
    return retval;
}




#pragma GCC diagnostic pop



